local outtmpfile = io.tmpfile();
local echar={
    r = '\r',
    n = '\n',
}

local function parse_jsonString(text,pos,out)
    if(text:sub(pos,pos+1)=='""')then
        return "",pos+2;
    end
    while(true)do
        local ps,pe,str,c,c2 = text:find('([^\\"]*)(.?)(.?)',pos+1);
        if(c=='"')then
            if(out)then
                out:write(str);
                local n = out:seek();
                out:seek('set');
                return out:read(n),pe;
            end
            return str,pe;
        elseif(c=='\\')then
            if(out==nil)then 
                out = outtmpfile; 
                out:seek("set");
            end;
            --写入文件中
            out:write(str);
            if(c2~=nil)then
                if(echar[c2])then
                    out:write(echar[c2]);
                else
                    out:write(c2);
                end
            end
            pos = pe;
        end
    end
end

function parse_json(text,pos)
    --local pos = 2;  --'{...'
    local json = {};
    while(true)do
        local pos_start,pos_end,c,c2 = text:find('%s*(.)(.?)',pos);
        --local pos_start,pos_end,e,key,p,value = text:find('%s*(}?),?"([%w_]+)":(.)',pos);
        
        if(c=='}')then
            return json,pos_start + 1;
        elseif(c=='{' and c2=='}')then
            return json,pos_end;
        end

        if(c2==nil or pos_end>=#text)then
            assert(nil);
        end
        assert(c==',' or c=='{')
        local pos_start,pos_end,key,p,value = text:find('%s*"([%w_]+)":%s*(.)',pos_end);
        assert(pos_start);
        if(p=="[")then
            --数组
            pos = text:find("%[",pos);
            json[key] = {};
            local list = json[key];
            while(true)do
                local pos_start,pos_end,p = text:find('%s*(.)',pos);
                if(p==']')then pos = pos_end+1; break; end;
                if(p=='[' or p==',')then
                else
                    xxx = 20;
                end
                assert(p=='[' or p==',');
                pos_start,pos_end,p = text:find('%s*(.)',pos_end+1);
                if(p==']')then
                    pos = pos_end+1;
                    break;
                elseif(p=='"')then
                    local ps,pe,value = text:find('([^"]*)..',pos_end+1);
                    table.insert(list,value);
                    pos = pe;
                elseif(p=='{')then
                    local j,pe = parse_json(text,pos_end);
                    table.insert(list,j);
                    pos = pe;
                else
                    local ps,pe,value = text:find('([^,}%]]+).',pos_end);
                    table.insert(list,value);
                    pos = pe;
                end
            end
        elseif(p=="{")then
            --下一个json
            local next_pos;
            json[key],next_pos = parse_json(text,pos_end);
            pos = next_pos;
        elseif(p=='"')then
            --local ps,pe,value = text:find('([^"]+)"',pos_end)
            local value,pe = parse_jsonString(text,pos_end);
            json[key] = value;
            pos = pe;
        else
            --布尔值或者数字,null
            local ps,pe,value = text:find('([^,%]%s}]+)%s*',pos_end);
            local bool = {
                ['true'] = true,
                ['false'] = false;
            };
            if(bool[value]~=nil)then 
                json[key] = bool[value]
            else
                json[key] = tonumber(value);
            end
            pos = pe + 1
        end
    end
end

local s = [[{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":29972,"rootPath":null,"rootUri":null,"capabilities":{"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","rename","delete"],"failureHandling":"textOnlyTransactional"},"didChangeConfiguration":{"dynamicRegistration":true},"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]}},"executeCommand":{"dynamicRegistration":true},"configuration":true,"workspaceFolders":true},"textDocument":{"publishDiagnostics":{"relatedInformation":true},"synchronization":{"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":true,"contextSupport":true,"completionItem":{"snippetSupport":true,"commitCharactersSupport":true,"documentationFormat":["markdown","plaintext"],"deprecatedSupport":true,"preselectSupport":true},"completionItemKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]}},"hover":{"dynamicRegistration":true,"contentFormat":["markdown","plaintext"]},"signatureHelp":{"dynamicRegistration":true,"signatureInformation":{"documentationFormat":["markdown","plaintext"]}},"definition":{"dynamicRegistration":true},"references":{"dynamicRegistration":true},"documentHighlight":{"dynamicRegistration":true},"documentSymbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"hierarchicalDocumentSymbolSupport":true},"codeAction":{"dynamicRegistration":true,"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["","quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}}},"codeLens":{"dynamicRegistration":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{"dynamicRegistration":true},"onTypeFormatting":{"dynamicRegistration":true},"rename":{"dynamicRegistration":true,"prepareSupport":true},"documentLink":{"dynamicRegistration":true},"typeDefinition":{"dynamicRegistration":true},"implementation":{"dynamicRegistration":true},"colorProvider":{"dynamicRegistration":true},"foldingRange":{"dynamicRegistration":true,"rangeLimit":5000,"lineFoldingOnly":true}}},"trace":"off","workspaceFolders":null}}]]
local v = parse_json(s);

function json_set(key,value)
    return string.format('%s:%s',key,value);
end

function json_obj(value)
    return '{' .. value .. '}'
end

function json_value_list(t)
    s = "["
    for k,v in ipairs(t)do
        if(s=='[')then
            s = s .. v;
        else
            s = s .. ',' .. v;
        end
    end
    return s .. ']';
end

function toJson(value,olist)
    local typ = type(value);
    if(typ=='string')then
        return '"' .. value .. '"';
    --elseif(type(v)=='boolean')then
    elseif(typ=='table')then
        if(#value~=0)then
            local s = "[";
            for k,v in ipairs(value)do
                if(k==1)then
                    s = s .. toJson(v);
                else
                    s = s .. ',' .. toJson(v);
                end
            end
            return s .. ']';
        else
            local s = "{";
            local idx = 1;
            local cma = '';
            if(olist)then
                
                for k,v in ipairs(olist)do
                    if(value[v]~=nil)then
                        local k = v;
                        v = toJson(value[v],olist);
                        s = s .. cma .. string.format('"%s":%s',k,v);
                        cma = ',';
                        value[k] = nil;
                    end
                end
            end

            for k,v in pairs(value)do
                v = toJson(v,olist);
                s = s .. cma .. string.format('"%s":%s',k,v);
                cma = ','
            end
            return s .. "}"
        end
    else
        return tostring(value);
    end
end

function toJsonFile(value,olist,out)
    local typ = type(value);
    if(typ=='string')then
        out:write('"',value,'"');
    elseif(typ=='table')then
        if(#value~=0)then
            out:write('[');
            for k,v in ipairs(value)do
                if(k==1)then
                    toJsonFile(v,olist,out);
                else
                    out:write(',');
                    toJsonFile(v,olist,out);
                end
            end
            out:write(']');
        else
            local idx = 1;
            local cma = '';
            out:write('{');
            if(olist)then
                
                for k,v in ipairs(olist)do
                    if(value[v]~=nil)then
                        local k = v;
                        --v = toJson(value[v],olist);
                        out:write(cma,'"',k,'"',':');
                        toJsonFile(value[v],olist,out);
                        cma = ',';
                        value[k] = nil;
                    end
                end
            end

            for k,v in pairs(value)do
                out:write(cma,'"',k,'"',":");
                toJsonFile(v,olist,out);

                cma = ','
            end
            out:write('}');
            return;
        end
    else
        out:write(tostring(value));
    end
end

